home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1993 / Internet Info CD-ROM (Walnut Creek) (1993).iso / networking / ip / ka9q / osrc.arc / TCPUSER.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-06-21  |  7.8 KB  |  366 lines

  1. /* User calls to TCP */
  2. #include "global.h"
  3. #include "timer.h"
  4. #include "mbuf.h"
  5. #include "netuser.h"
  6. #include "socket.h"
  7. #include "internet.h"
  8. #include "tcp.h"
  9. #include "icmp.h"
  10.  
  11. void send_syn(),unlink_tcb(),tcp_timeout();
  12.  
  13. int16 Tcp_window = DEF_WND;
  14.  
  15. struct tcb *
  16. open_tcp(lsocket,fsocket,mode,window,r_upcall,t_upcall,s_upcall,tos,user)
  17. struct socket *lsocket;    /* Local socket */
  18. struct socket *fsocket;    /* Remote socket */
  19. int mode;        /* Active/passive/server */
  20. int16 window;        /* Receive window (and send buffer) sizes */
  21. void (*r_upcall)();    /* Function to call when data arrives */
  22. void (*t_upcall)();    /* Function to call when ok to send more data */
  23. void (*s_upcall)();    /* Function to call when connection state changes */
  24. int tos;
  25. int user;        /* User linkage area */
  26. {
  27.     struct connection conn;
  28.     register struct tcb *tcb;
  29.  
  30.     if(lsocket == NULLSOCK){
  31.         Net_error = INVALID;
  32.         return NULLTCB;
  33.     }
  34.     conn.local.address = lsocket->address;
  35.     conn.local.port = lsocket->port;
  36.     if(fsocket != NULLSOCK){
  37.         conn.remote.address = fsocket->address;
  38.         conn.remote.port = fsocket->port;
  39.     } else {
  40.         conn.remote.address = 0;
  41.         conn.remote.port = 0;
  42.     }
  43.     if((tcb = lookup_tcb(&conn)) == NULLTCB){
  44.         if((tcb = create_tcb(&conn)) == NULLTCB){
  45.             Net_error = NO_SPACE;
  46.             return NULLTCB;
  47.         }
  48.     } else if(tcb->state != LISTEN){
  49.         Net_error = CON_EXISTS;
  50.         return NULLTCB;
  51.     }
  52.     tcb->user = user;
  53.     if(window != 0)
  54.         tcb->window = tcb->rcv.wnd = window;
  55.     else
  56.         tcb->window = tcb->rcv.wnd = Tcp_window;
  57.     tcb->snd.wnd = 1;    /* Allow space for sending a SYN */
  58.     tcb->r_upcall = r_upcall;
  59.     tcb->t_upcall = t_upcall;
  60.     tcb->s_upcall = s_upcall;
  61.     tcb->tos = tos;
  62.     switch(mode){
  63.     case TCP_SERVER:
  64.         tcb->flags.clone = 1;
  65.     case TCP_PASSIVE:    /* Note fall-thru */
  66.         setstate(tcb,LISTEN);
  67.         break;
  68.     case TCP_ACTIVE:
  69.         /* Send SYN, go into SYN_SENT state */
  70.         tcb->flags.active = 1;
  71.         send_syn(tcb);
  72.         setstate(tcb,SYN_SENT);
  73.         tcp_output(tcb);
  74.         Tcp_stat.conout++;
  75.         break;
  76.     }
  77.     return tcb;
  78. }
  79. /* User send routine */
  80. int
  81. send_tcp(tcb,bp)
  82. register struct tcb *tcb;
  83. struct mbuf *bp;
  84. {
  85.     int16 cnt;
  86.  
  87.     if(tcb == NULLTCB || bp == NULLBUF){
  88.         free_p(bp);
  89.         Net_error = INVALID;
  90.         return -1;
  91.     }
  92.     cnt = len_mbuf(bp);
  93.     switch(tcb->state){
  94.     case CLOSED:
  95.         free_p(bp);
  96.         Net_error = NO_CONN;
  97.         return -1;
  98.     case LISTEN:
  99.         if(tcb->conn.remote.address == 0 && tcb->conn.remote.port == 0){
  100.             /* Save data for later */
  101.             append(&tcb->sndq,bp);
  102.             tcb->sndcnt += cnt;
  103.             break;
  104.         }        
  105.         /* Change state from passive to active */
  106.         tcb->flags.active = 1;
  107.         send_syn(tcb);
  108.         setstate(tcb,SYN_SENT);    /* Note fall-thru */
  109.     case SYN_SENT:
  110.     case SYN_RECEIVED:
  111.     case ESTABLISHED:
  112.     case CLOSE_WAIT:
  113.         append(&tcb->sndq,bp);
  114.         tcb->sndcnt += cnt;
  115.         tcp_output(tcb);
  116.         break;
  117.     case FINWAIT1:
  118.     case FINWAIT2:
  119.     case CLOSING:
  120.     case LAST_ACK:
  121.     case TIME_WAIT:
  122.         free_p(bp);
  123.         Net_error = CON_CLOS;
  124.         return -1;
  125.     }
  126.     return cnt;
  127. }
  128. /* User receive routine */
  129. int
  130. recv_tcp(tcb,bpp,cnt)
  131. register struct tcb *tcb;
  132. struct mbuf **bpp;
  133. int16 cnt;
  134. {
  135.     if(tcb == NULLTCB || bpp == (struct mbuf **)NULL){
  136.         Net_error = INVALID;
  137.         return -1;
  138.     }
  139.     if(tcb->rcvcnt == 0){
  140.         /* If there's nothing on the queue, our action depends on what state
  141.          * we're in (i.e., whether or not we're expecting any more data).
  142.          * If no more data is expected, then simply return 0; this is
  143.          * interpreted as "end of file". Otherwise return -1.
  144.          */
  145.         switch(tcb->state){
  146.         case LISTEN:
  147.         case SYN_SENT:
  148.         case SYN_RECEIVED:
  149.         case ESTABLISHED:
  150.         case FINWAIT1:
  151.         case FINWAIT2:
  152.             Net_error = WOULDBLK;
  153.             return -1;
  154.         case CLOSED:
  155.         case CLOSE_WAIT:
  156.         case CLOSING:
  157.         case LAST_ACK:
  158.         case TIME_WAIT:
  159.             *bpp = NULLBUF;
  160.             return 0;
  161.         }
  162.     }
  163.     /* cnt == 0 means "I want it all" */
  164.     if(cnt == 0)
  165.         cnt = tcb->rcvcnt;
  166.     /* See if the user can take all of it */
  167.     if(tcb->rcvcnt <= cnt){
  168.         cnt = tcb->rcvcnt;
  169.         *bpp = tcb->rcvq;
  170.         tcb->rcvq = NULLBUF;
  171.     } else {
  172.         if((*bpp = alloc_mbuf(cnt)) == NULLBUF){
  173.             Net_error = NO_SPACE;
  174.             return -1;
  175.         }
  176.         pullup(&tcb->rcvq,(*bpp)->data,cnt);
  177.         (*bpp)->cnt = cnt;
  178.     }
  179.     tcb->rcvcnt -= cnt;
  180.     tcb->rcv.wnd += cnt;
  181.     /* Do a window update if it was closed */
  182.     if(cnt == tcb->rcv.wnd){
  183.         tcb->flags.force = 1;
  184.         tcp_output(tcb);
  185.     }
  186.     return cnt;
  187. }
  188. /* This really means "I have no more data to send". It only closes the
  189.  * connection in one direction, and we can continue to receive data
  190.  * indefinitely.
  191.  */
  192. int
  193. close_tcp(tcb)
  194. register struct tcb *tcb;
  195. {
  196.     if(tcb == NULLTCB){
  197.         Net_error = INVALID;
  198.         return -1;
  199.     }
  200.     switch(tcb->state){
  201.     case CLOSED:
  202.         return 0;    /* Unlikely */
  203.     case LISTEN:
  204.     case SYN_SENT:
  205.         close_self(tcb,NORMAL);
  206.         return 0;
  207.     case SYN_RECEIVED:
  208.     case ESTABLISHED:
  209.         tcb->sndcnt++;
  210.         tcb->snd.nxt++;
  211.         setstate(tcb,FINWAIT1);
  212.         tcp_output(tcb);
  213.         return 0;
  214.     case CLOSE_WAIT:
  215.         tcb->sndcnt++;
  216.         tcb->snd.nxt++;
  217.         setstate(tcb,LAST_ACK);
  218.         tcp_output(tcb);
  219.         return 0;
  220.     case FINWAIT1:
  221.     case FINWAIT2:
  222.     case CLOSING:
  223.     case LAST_ACK:
  224.     case TIME_WAIT:
  225.         Net_error = CON_CLOS;
  226.         return -1;
  227.     }
  228.     return -1;    /* "Can't happen" */
  229. }
  230. /* Delete TCB, free resources. The user is not notified, even if the TCB is
  231.  * not in the CLOSED state. This function should normally be called by the
  232.  * user only in response to a state change upcall to CLOSED state.
  233.  */
  234. int
  235. del_tcp(tcb)
  236. register struct tcb *tcb;
  237. {
  238.     struct reseq *rp,*rp1;
  239.  
  240.     if(tcb == NULLTCB){
  241.         Net_error = INVALID;
  242.         return -1;
  243.     }
  244.     unlink_tcb(tcb);
  245.     stop_timer(&tcb->timer);
  246.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  247.         rp1 = rp->next;
  248.         free_p(rp->bp);
  249.         free((char *)rp);
  250.     }
  251.     tcb->reseq = NULLRESEQ;
  252.     free_p(tcb->rcvq);
  253.     free_p(tcb->sndq);
  254.     free((char *)tcb);
  255.     return 0;
  256. }
  257. /* Return 1 if arg is a valid TCB, 0 otherwise */
  258. int
  259. tcpval(tcb)
  260. struct tcb *tcb;
  261. {
  262.     register int i;
  263.     register struct tcb *tcb1;
  264.  
  265.     if(tcb == NULLTCB)
  266.         return 0;    /* Null pointer can't be valid */
  267.     for(i=0;i<NTCB;i++){
  268.         for(tcb1=Tcbs[i];tcb1 != NULLTCB;tcb1 = tcb1->next){
  269.             if(tcb1 == tcb)
  270.                 return 1;
  271.         }
  272.     }
  273.     return 0;
  274. }
  275. /* Kick a particular TCP connection */
  276. int
  277. kick_tcp(tcb)
  278. register struct tcb *tcb;
  279. {
  280.     if(!tcpval(tcb))
  281.         return -1;
  282.     tcp_timeout((char *)tcb);
  283.     return 0;
  284. }
  285. /* Kick all TCP connections to specified address */
  286. void
  287. kick(addr)
  288. int32 addr;
  289. {
  290.     register int i;
  291.     register struct tcb *tcb;
  292.  
  293.     for(i=0;i<NTCB;i++){
  294.         for(tcb=Tcbs[i];tcb != NULLTCB;tcb = tcb->next){
  295.             if(tcb->conn.remote.address == addr)
  296.                 kick_tcp(tcb);
  297.         }
  298.     }
  299. }
  300. /* Clear all TCP connections */
  301. void
  302. reset_all()
  303. {
  304.     register int i;
  305.     register struct tcb *tcb;
  306.  
  307.     for(i=0;i<NTCB;i++){
  308.         for(tcb=Tcbs[i];tcb != NULLTCB;tcb = tcb->next)
  309.             reset_tcp(tcb);
  310.     }
  311.     pwait(NULL);    /* Let the RSTs go forth */
  312. }
  313. void
  314. reset_tcp(tcb)
  315. register struct tcb *tcb;
  316. {
  317.     struct tcp fakeseg;
  318.  
  319.     if(tcb == NULLTCB)
  320.         return;
  321.     if(tcb->state != LISTEN){
  322.         /* Compose a fake segment with just enough info to generate the
  323.          * correct RST reply
  324.          */
  325.         fakeseg.flags.rst = 0;
  326.         fakeseg.dest = tcb->conn.local.port;
  327.         fakeseg.source = tcb->conn.remote.port;
  328.         fakeseg.flags.ack = 1;
  329.         /* Here we try to pick a sequence number with the greatest likelihood
  330.          * of being in his receive window.
  331.          */
  332.         fakeseg.ack = tcb->snd.nxt + tcb->snd.wnd - 1;
  333.         reset(tcb->conn.remote.address,
  334.             tcb->conn.local.address,
  335.             0,0,&fakeseg);
  336.     }
  337.     close_self(tcb,RESET);
  338. }
  339. /* Return character string corresponding to a TCP well-known port, or
  340.  * the decimal number if unknown.
  341.  */
  342. char *
  343. tcp_port(n)
  344. int16 n;
  345. {
  346.     static char buf[32];
  347.  
  348.     switch(n){
  349.     case IPPORT_ECHO:
  350.         return "echo";
  351.     case IPPORT_DISCARD:
  352.         return "discard";
  353.     case IPPORT_FTPD:
  354.         return "ftp_data";
  355.     case IPPORT_FTP:
  356.         return "ftp";    
  357.     case IPPORT_TELNET:
  358.         return "telnet";
  359.     case IPPORT_SMTP:
  360.         return "smtp";
  361.     default:
  362.         sprintf(buf,"%u",n);
  363.         return buf;
  364.     }
  365. }
  366.